﻿using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Jerry
{
    /// <summary>
    /// <para>AssetBundle加载操作</para>
    /// <para>加载资源(Asset)的时候，等候AssetBundle的加载成功，再去AssetBundle里加载</para>
    /// </summary>
    public abstract class JABLoadOperation : IEnumerator
    {
        #region 实现IEnumerator

        public object Current { get { return null; } }

        public bool MoveNext()
        {
            return !IsDone();
        }

        public void Reset() { }

        #endregion 实现IEnumerator

        /// <summary>
        /// <para>等候m_Request构建好</para>
        /// <para>返回值表示是否还需要更新</para>
        /// <para>出错了将不再更新</para>
        /// </summary>
        /// <returns></returns>
        abstract public bool Update();

        /// <summary>
        /// <para>是否加载完成</para>
        /// <para>为了避免阻塞，报错了是true</para>
        /// </summary>
        /// <returns></returns>
        abstract public bool IsDone();

        /// <summary>
        /// 进度
        /// </summary>
        /// <returns></returns>
        abstract public float Progress();

        /// <summary>
        /// 资源请求
        /// </summary>
        /// <returns></returns>
        abstract public AsyncOperation GetRequest();
    }

    /// <summary>
    /// 资源加载操作
    /// </summary>
    public class JABLoadResOperation : JABLoadOperation
    {
        protected string m_AssetBundleName = null;
        protected string m_DownloadingError = null;
        /// <summary>
        /// 加载好的Bundle
        /// </summary>
        protected AssetBundle m_LoadedAssetbundle = null;
        /// <summary>
        /// Asset加载请求，从Bundle里请求或有Bundle后请求
        /// </summary>
        protected AsyncOperation m_Request = null;

        public JABLoadResOperation(string assetbundleName)
        {
            m_AssetBundleName = assetbundleName;
        }

        public override AsyncOperation GetRequest()
        {
            return m_Request;
        }

        /// <summary>
        /// true表示还要子类处理
        /// </summary>
        /// <returns></returns>
        public override bool Update()
        {
            if (JABMgr.Inst.PauseLoading)
            {
                return false;
            }

            if (GetRequest() != null)
            {
                return false;
            }

            m_LoadedAssetbundle = JABMgr.Inst.GetLoadedAssetBundle(m_AssetBundleName, out m_DownloadingError);
            if (m_LoadedAssetbundle == null
                && m_DownloadingError != null)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 是否完成
        /// </summary>
        /// <returns></returns>
        public override bool IsDone()
        {
            if (JABMgr.Inst.PauseLoading)
            {
                return true;
            }
            if (GetRequest() == null && m_DownloadingError != null)
            {
                return true;
            }
            return GetRequest() != null && GetRequest().isDone;
        }

        /// <summary>
        /// 进度
        /// </summary>
        /// <returns></returns>
        public override float Progress()
        {
            if (JABMgr.Inst.PauseLoading)
            {
                return 1.0f;
            }
            if (GetRequest() == null)
            {
                return 0.0f;
            }
            if (GetRequest().isDone)
            {
                return 1.0f;
            }
            return GetRequest().progress;
        }
    }

    /// <summary>
    /// Level加载操作
    /// </summary>
    public class JABLoadLevelOperation : JABLoadResOperation
    {
        protected string m_LevelName;
        protected bool m_IsAdditive;

        public JABLoadLevelOperation(string assetbundleName, string levelName, bool isAdditive)
            : base(assetbundleName)
        {
            m_LevelName = levelName;
            m_IsAdditive = isAdditive;
        }

        public override bool Update()
        {
            if (base.Update() == false)
            {
                return false;
            }

            if (m_LoadedAssetbundle != null)
            {
                m_Request = SceneManager.LoadSceneAsync(m_LevelName, m_IsAdditive ? LoadSceneMode.Additive : LoadSceneMode.Single);
                m_Request.allowSceneActivation = true;
                return false;
            }
            else
            {
                return true;
            }
        }
    }

    /// <summary>
    /// Asset加载操作
    /// </summary>
    public class JABLoadAssetOperation : JABLoadResOperation
    {
        protected string m_AssetName;
        protected System.Type m_Type;
        protected new AssetBundleRequest m_Request = null;
        public string AssetKey = "";

        public JABLoadAssetOperation(string bundleName, string assetName, System.Type type)
            : base(bundleName)
        {
            AssetKey = bundleName + "." + assetName;
            m_AssetName = assetName;
            m_Type = type;
        }

        public override AsyncOperation GetRequest()
        {
            return m_Request;
        }

        public T GetAsset<T>() where T : UnityEngine.Object
        {
            if (JABMgr.Inst.PauseLoading)
            {
                return null;
            }
            if (GetRequest() != null && GetRequest().isDone)
            {
                return (GetRequest() as AssetBundleRequest).asset as T;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Returns true if more Update calls are required.
        /// </summary>
        /// <returns></returns>
        public override bool Update()
        {
            if (base.Update() == false)
            {
                return false;
            }

            if (m_LoadedAssetbundle != null)
            {
                m_Request = m_LoadedAssetbundle.LoadAssetAsync(m_AssetName, m_Type);
                return false;
            }
            else
            {
                return true;
            }
        }
    }

    public class JABLoadManifestOperation : JABLoadAssetOperation
    {
        public JABLoadManifestOperation(string bundleName, string assetName, System.Type type)
            : base(bundleName, assetName, type)
        {
        }

        /// <summary>
        /// Manifest的特殊化处理
        /// </summary>
        /// <returns></returns>
        public override bool Update()
        {
            base.Update();
            if (m_Request != null && m_Request.isDone)
            {
                JABMgr.AssetBundleManifestObject = GetAsset<AssetBundleManifest>();
                return false;
            }
            else
            {
                return true;
            }
        }
    }
}